import datetime
import threading
import json
import time

from libs.comps.common.component import manager , TComponentManager , TComponent
from libs.comps.common.compDB import TCompDB
from libs.comps.common.compKV import TCompKV
from libs.utils.mqtt_utils import TMqtt
from libs.utils.ice645_utils import TUtils645
import os.path


class TIotDtu645 ( TComponent):

    def __init__(self , _manager):
        super().__init__(_manager)
        self.info={
            "mqSvrs":{},
            "dtus":{},
            "variants":{}
        }
        self.mqClients ={}
        self.resetClientTime = 0
        self.sendBytes ={}
    @property
    def db(self):
        res: TCompDB= None
        try:
            dbCode = self.compSettings['dbCode']
            res = self.manager.getComp("TCompDB" , dbCode)
        except Exception as er :
            self.manager.log(self , er)
        return res
    @property
    def kv(self):
        res: TCompKV= None
        try:
            code = self.compSettings['compKvCode']
            res = self.manager.getComp("TCompKV" , code)
        except Exception as er :
            self.manager.log(self , er)
        return res
    def loadTasks(self):
        try:
            self.resetClientTime = time.time()
            self.closeMqClients()
            taskRes = self.db.queryByKey('iot/dtu645_dtu_vars',{})
            if taskRes['queryStatus'] == 1 :
                tasks = taskRes['datasetList'][0]
                for item in tasks:
                    dtuCode = item['dtuCode']
                    item['lastTime'] = 0
                    self.info['dtus'][dtuCode] = item
                vars = taskRes['datasetList'][1]
                for var in vars:
                    vk = f"{var['meterCode']}_{var['varCode']}"
                    self.info['variants'][vk] = var
        except Exception as er:
            self.manager.log(self , er)
    def closeMqClients(self):
        try:
            for client in self.mqClients.values():
                try:
                    client.disconnect()
                    client = None
                except Exception as err:
                    self.manager.log(self , err)
            self.mqClients.clear()
        except Exception as er:
            self.manager.log(self , er)
    def resetMqClients(self):
        try:
            self.resetClientTime = time.time()
            self.closeMqClients()
            mqRes = self.db.queryByKey('iot/dtu645_mqsvr',{})
            if mqRes['queryStatus'] == 1 :
                items = mqRes['datasetList'][0]
                for item in items:
                    mqSvrCode = item['mqSvrCode']
                    subTopics = json.loads(item['subTopics'])
                    item['subTopics'] =[x['topic'] for x in subTopics]
                    self.info['mqSvrs'][mqSvrCode] = item
                    client = TMqtt.newMqtt(
                        host= item['host'] ,
                        port= item['port'] ,
                        uid= item['uid'] ,
                        pwd= item['pwd'] ,
                        topics= item['subTopics'] ,
                        onMsg= self.onMessage
                    )
                    self.mqClients[mqSvrCode] = client
                    client.connect()
        except Exception as er:
            self.manager.log(self , er)
    def onMessage(self , message , client):
        try:
            topic = message.topic
            payload = message.payload
            if len(payload)> 10:
                msgInfo = TUtils645.decode645(payload)
                if msgInfo['status'] ==1 :
                    meterCode = msgInfo['addr']
                    varCode = msgInfo['itemCode']
                    valueStr = msgInfo['valueStr']
                    vk = f"{meterCode}_{varCode}"

                    if vk in self.info['variants'].keys():
                        varInfo = self.info['variants'][vk]
                        negativeFlag = varInfo['negative']
                        decSize = varInfo['decSize']
                        rate = varInfo['r1']
                        value = TUtils645.parse645Value(valueStr , negativeFlag, decSize, rate )
                        bucketCode = varInfo['sysCode']
                        self.kv.setValue(bucketCode , meterCode , varCode , value)
                    else:
                        print(f"var key error.")
        except Exception as er:
            self.manager.log(self , f"onMessage :{er}")
    def sendMsgs(self ):
        try:
            for dtu in self.info['dtus'].values():
                mqSvrCode = dtu['mqSvrCode']
                dlt  = time.time() - dtu['lastTime']
                if mqSvrCode in self.mqClients.keys() and  dlt> 3 :
                    dtu['lastTime'] = time.time()
                    mqClient:TMqtt = self.mqClients[mqSvrCode]
                    dtuCode = dtu['dtuCode']
                    topic = dtu['downTopic']
                    taskPath = f"{self.compSettings['taskPath']}/{dtuCode}"
                    if os.path.exists(taskPath):
                        taskFns = os.listdir(taskPath)
                        if len(taskFns)>0:
                            taskFn = taskFns[0]
                        #for taskFn in taskFns:
                            data = (taskFn[:-5]).split("_")
                            meterCode = data[1]
                            varCode = data[2]

                            key = f"{meterCode}_{varCode}"
                            if key not in self.sendBytes.keys():
                                self.sendBytes[key] = TUtils645.encode645(meterCode , varCode)
                            sendBytes = self.sendBytes[key]
                            mqClient.client.publish(topic , sendBytes)
                            fullFn = os.path.join(taskPath , taskFn)
                            os.remove(fullFn)
        except Exception as er:
            self.manager.log(self , er)
    def recMsgs(self ):
        try:
            pass
        except Exception as er:
            self.manager.log(self , er)
    def serviceHandler(self):
        try:
            super().serviceHandler()
            while self.running :
                try:
                    time.sleep(1)
                    self.sendMsgs()

                    nowTime = time.time()
                    dltResetTime = nowTime - self.resetClientTime
                    if dltResetTime>4*24*3600 :
                        self.resetMqClients()
                except Exception as erLoop:
                    self.manager.log(self , erLoop)
        except Exception as erBrfore:
            self.manager.log(self, erBrfore)
    def beforeStartService(self):
        try:
            super().beforeStartService()
            self.loadTasks()
            self.resetMqClients()
        except Exception as er:
            self.manager.log(self, er)
    def startService(self):
        try:
            if not self.running:
                try:
                    self.beforeStartService()
                except Exception as erBrfore:
                    self.manager.log(self, erBrfore)
                self.serviceThread = threading.Thread(target=self.serviceHandler, daemon=True)
                self.running = True
                self.serviceThread.start()
        except Exception as er:
            self.manager.log(self, er)
    def stopService(self):
        try:
            self.running = False
            self.closeMqClients()
        except Exception as er:
            self.manager.log(self, er)
manager.registCompType("TIotDtu645", TIotDtu645)